package com.huitone.gddw.controller.worktable;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.huitone.gddw.common.excel.CreateExcel;
import com.huitone.gddw.controller.common.CommonController;
import com.huitone.gddw.dao.entity.PrgDispatchNotify;
import com.huitone.gddw.dao.entity.PrgDispatchNotify.DispatchResult;
import com.huitone.gddw.dao.entity.PrgDispatchNotify.DispatchStatus;
import com.huitone.gddw.dao.entity.PrgDispatchNotify.NotifyType;
import com.huitone.gddw.dao.entity.PrgExtInfo;
import com.huitone.gddw.dao.entity.PrgInfo;
import com.huitone.gddw.dao.entity.PrgRunningStatus;
import com.huitone.gddw.dao.entity.SmLog;
import com.huitone.gddw.dao.entity.PrgRunningStatus.RunningStatus;
import com.huitone.gddw.model.support.Message;
import com.huitone.gddw.model.support.QueryPage;
import com.huitone.gddw.service.IPrgDispatchNotifyService;
import com.huitone.gddw.service.IPrgExtInfoService;
import com.huitone.gddw.service.IPrgInfoService;
import com.huitone.gddw.service.IPrgRunningStatusService;
import com.huitone.gddw.service.dto.PrgInfoDTO;
import com.huitone.gddw.utils.ContextPropertiesUtils;
import com.huitone.gddw.utils.SysLoginUtil;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

/**
 * 项目模块控制器
 * @author wuluodan
 *
 */
@Controller
@RequestMapping(value="program")
public class PrgInfoController extends CommonController {

	private final static Logger LOGGER = Logger.getLogger(PrgInfoController.class);
	
	@Autowired
	private IPrgInfoService prgInfoService;
	
	@Autowired
	private IPrgRunningStatusService prgRunningStatusService;
	
	@Autowired
	private IPrgExtInfoService prgExtInfoService;
	
	@Autowired
	private IPrgDispatchNotifyService prgDispatchNotifyService;
	
	/**
	 * 程序运行管理查询
	 * @param page
	 * @return QueryPage
	 */
	@ResponseBody
	@RequestMapping(value="query")
	public QueryPage<PrgInfoDTO> query(QueryPage<PrgInfo> page, HttpServletRequest request) {
		super.logType = SmLog.LOGTYPE_SELECT;
		super.logContent = "[" + SysLoginUtil.getLoginUserId() + "]查询程序信息";
		Map<String, Object> params = new HashMap<String, Object>();
		String deployId = request.getParameter("deployId");
		String prgName = request.getParameter("prgName");
		params.put("deployId", deployId);
		params.put("prgName", prgName);
		page.setParams(params);
		QueryPage<PrgInfoDTO> result = null;
		try {
			result = prgInfoService.selectPage(page);
		} catch (Exception e) {
			LOGGER.error("查询程序信息出现异常：" + e.getMessage(), e);
			super.logResult = SmLog.RESULT_FAIL;
		}
		super.saveSmLog(super.logType, super.logContent, super.logResult);
		return result;
	}
	
	/**
	 * 更新程序状态
	 * @param prgId 程序ID
	 * @param notifyType 通知类型
	 * @return Message
	 */
	@ResponseBody
	@RequestMapping(value="changeStatus")
	public Message changeStatus(String prgId, String notifyType) {
		try {
			PrgRunningStatus prgRunningStatus = prgRunningStatusService.selectByPrimaryKey(prgId);
			if (prgRunningStatus != null) {
				if (prgRunningStatus.getRunningStatus().equals(notifyType)) {
					if (notifyType.equals(RunningStatus.RUNNINGSTATUS_RUN.getCode())) {
						return new Message(false, "该程序已是 启动 状态，无需再次启动！");
					}
					if (notifyType.equals(RunningStatus.RUNNINGSTATUS_PAUSE.getCode())) {
						return new Message(false, "该程序已是 暂停 状态，无需再次暂停！");
					}
					if (notifyType.equals(RunningStatus.RUNNINGSTATUS_STOP.getCode())) {
						return new Message(false, "该程序已是 停止 状态，无需再次停止！");
					}
				}
				if (notifyType.equals(NotifyType.OVERLOAD.getCode()) && 
						prgRunningStatus.getRunningStatus().equals(RunningStatus.RUNNINGSTATUS_STOP.getCode())) {
					return new Message(false, "该程序处于停止状态，无法重载！");
				}
			}
			
			PrgDispatchNotify prgDispatchNotify = prgDispatchNotifyService.getLastByPrgId(prgId);
			if (prgDispatchNotify != null && !prgDispatchNotify.getDispatchStatus().equals(DispatchStatus.COMPLETED.getCode())) {
				return new Message(false, "该程序未完成上次调度，无法再次操作！");
			}
			
			int code = saveAndWait(prgId, notifyType);
			
			if (1 == code) {
				return new Message(false, "该程序未启动调度！");
			}
			if (2 == code) {
				return new Message(false, "该程序未完成调度！");
			}
			if (3 == code) {
				return new Message(false, "调度失败！");
			}
			return new Message(true, "调度成功！");
		} catch (Exception e) {
			LOGGER.error("启动/暂停/停止/重载程序出现异常：" + e.getMessage(), e);
			return new Message(false, "操作失败！");
		}
	}
	
	/**
	 * 准备修改页面的信息
	 * @param prgId 程序id
	 * @return PrgInfoDTO
	 */
	@ResponseBody
	@RequestMapping(value="toUpdate")
	public PrgInfoDTO toUpdate(String prgId) {
		PrgInfoDTO prgInfoDTO = prgInfoService.toUpadte(prgId);
		return prgInfoDTO;
	}
	
	/**
	 * 新增/修改程序信息
	 * @param entity 程序模块信息
	 * @param request
	 * @return Message
	 */
	@ResponseBody
	@RequestMapping(value="saveOrUpdate")
	public Message saveOrUpdate(PrgInfo entity, HttpServletRequest request) {
		super.logType = SmLog.LOGTYPE_UPDATE;
		super.logContent = "[" + SysLoginUtil.getLoginUserId() + "]添加/修改程序信息";
		if (StringUtils.isBlank(entity.getPrgId())) {
			super.saveSmLog(super.logType, super.logContent, SmLog.RESULT_FAIL);
			return new Message(false, "程序id不能为空！");
		}
		boolean isSave = false; // 保存操作标识
		isSave = request.getParameter("isSave") == null ? false : Boolean.valueOf(request.getParameter("isSave"));
		try {
			PrgInfo prgInfo = prgInfoService.selectByPrimaryKey(entity.getPrgId());
			if (isSave) {
				if (prgInfo != null) {
					super.saveSmLog(super.logType, super.logContent, SmLog.RESULT_FAIL);
					return new Message(false, "该程序id已存在，不能重复添加！");
				}
			} else {
				// 同步更新信息
				prgInfo.setPrgName(entity.getPrgName());
				prgInfo.setDeployId(entity.getDeployId());
				prgInfo.setDeployDir(entity.getDeployDir());
				prgInfo.setDesc(entity.getDesc());
				prgInfo.setGroupName(entity.getGroupName());
				prgInfo.setModuleName(entity.getModuleName());
			}
			
			List<PrgExtInfo> listSaveExt = new ArrayList<PrgExtInfo>(); 	// 存储需要保存的参数记录
			List<PrgExtInfo> listUpdateExt = new ArrayList<PrgExtInfo>(); 	// 存储需要更新的参数记录
			List<String> listRecId = new ArrayList<String>(); 				// 存储当前更新的参数id
			// 获取程序所有参数信息
			String prgExtInfos = URLDecoder.decode(request.getParameter("prgExtInfos"), "UTF-8");
			JSONArray ja = JSONArray.fromObject(prgExtInfos);
			// 遍历每条参数信息
			for (int i = 0; i < ja.size(); i++) {
				PrgExtInfo prgExtInfo;
				JSONObject jb = ja.getJSONObject(i);
				String recId = jb.getString("recId");
				String paramName = jb.getString("paramName");
				String paramNameCn = jb.getString("paramNameCn");
				String paramValue = jb.getString("paramValue");
				// 程序id为空时，添加参数信息，否则更新
				if (StringUtils.isBlank(recId)) {
					prgExtInfo = new PrgExtInfo();
					prgExtInfo.setPrgId(entity.getPrgId());
					prgExtInfo.setParamName(paramName);
					prgExtInfo.setParamNameCn(paramNameCn);
					prgExtInfo.setParamValue(paramValue);
					listSaveExt.add(prgExtInfo);
				} else {
					prgExtInfo = prgExtInfoService.selectByPrimaryKey(recId);
					// 参数名、中文名、参数值不变时，不作更新
					if (paramName.equals(prgExtInfo.getParamName()) && paramNameCn.equals(prgExtInfo.getParamNameCn()) 
							&& paramValue.equals(prgExtInfo.getParamValue())) {
						listRecId.add(recId);
						continue;
					} else {
						prgExtInfo.setRecId(recId);
						prgExtInfo.setPrgId(entity.getPrgId());
						prgExtInfo.setParamName(paramName);
						prgExtInfo.setParamNameCn(paramNameCn);
						prgExtInfo.setParamValue(paramValue);
						listUpdateExt.add(prgExtInfo);
					}
					listRecId.add(recId);
				}
				
			}
			
			String notifyMsg = null;
			if (isSave) {
				prgInfoService.save(entity, listSaveExt);
			} else {
				List<PrgExtInfo> listExtInfo = prgExtInfoService.selectByPrgId(entity.getPrgId());
				List<PrgExtInfo> listDelExt = new ArrayList<PrgExtInfo>(); 		// 存储需要删除的参数记录
				for (PrgExtInfo prgExtInfo : listExtInfo) {
					if (listRecId.contains(prgExtInfo.getRecId())) {
						continue;
					} else {
						listDelExt.add(prgExtInfo);
					}
				}
				prgInfoService.update(prgInfo, listSaveExt, listUpdateExt, listDelExt);
				
				 //参数改变时，重新调度
				if (listSaveExt.size() > 0 || listUpdateExt.size() > 0 || listDelExt.size() > 0) {
					int code = saveAndWait(prgInfo.getPrgId(), NotifyType.OVERLOAD.getCode());
					if (1 == code) {
						notifyMsg = "但未启动调度！";
					}
					if (2 == code) {
						notifyMsg = "但未完成调度！";
					}
					if (3 == code) {
						notifyMsg = "但调度失败！";
					}
				}
			}
			super.saveSmLog(super.logType, super.logContent, super.logResult);
			return notifyMsg == null ? new Message(true, "保存成功！") : new Message(true, "保存成功！" + notifyMsg);
		} catch (Exception e) {
			LOGGER.error("保存程序信息过程中出现异常：" + e.getMessage(), e);
			super.saveSmLog(super.logType, super.logContent, SmLog.RESULT_FAIL);
			return new Message(false, "保存失败！");
		}
	}
	
	/**
	 * 删除程序信息
	 * @param prgId 程序id
	 * @return Message
	 */
	@ResponseBody
	@RequestMapping(value="delete")
	public Message delete(String prgId) {
		super.logType = SmLog.LOGTYPE_DELETE;
		super.logContent = "[" + SysLoginUtil.getLoginUserId() + "]删除程序";
		try {
			prgInfoService.delete(prgId);
			super.saveSmLog(super.logType, super.logContent, super.logResult);
			return new Message(true, "删除成功！");
		} catch (Exception e) {
			LOGGER.error("删除程序信息过程中出现异常：" + e.getMessage(), e);
			super.saveSmLog(super.logType, super.logContent, SmLog.RESULT_FAIL);
			return new Message(false, "删除失败！");
		}
	}
	
	/**
	 * 导出 Excel
	 * @param request
	 * @param response
	 */
	@RequestMapping(value="/out-excel", method=RequestMethod.POST)
	public void outExcel(HttpServletRequest request, HttpServletResponse response) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
		String fileName = "程序信息表";
		
		Map<String, Object> params = new HashMap<String, Object>();
		for (Object name : request.getParameterMap().keySet()) {
			params.put(name.toString(), request.getParameter(name.toString()));
		}
		
		List<PrgInfoDTO> list = prgInfoService.getRecord(params);
		if (null == list || 0 == list.size()) {
			list.add(new PrgInfoDTO());
		}
		
		HSSFWorkbook wb = (HSSFWorkbook)CreateExcel
				.getInstance()
				.CreateNewExcelNoTemplate(fileName, list).getWorkbook();
		OutputStream fOut = null;
		try {
			fileName = new String(fileName.getBytes("gbk"), "ISO8859-1");
			response.reset();
			response.setContentType("application/octet-stream; charset=utf-8");
			response.setHeader("Content-Disposition",
					"attachment;filename="+fileName+sdf.format(new Date())+".xls");
			fOut = response.getOutputStream();
			wb.write(fOut);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				fOut.flush();
				fOut.close();
			} catch (IOException e) {

			}
		}
	}
	
	public static void main(String[] args) {
//		query(new QueryPage<PrgInfo>());
	}
	
	/**
	 * 监听程序等待调度过程
	 * @param prgId 程序ID
	 * @param notifyType 调度类型
	 * @return Integer 调度结果代码
	 */
	private Integer saveAndWait(String prgId, String notifyType) {
		// 新增调度信息
		PrgDispatchNotify entity = new PrgDispatchNotify();
		entity.setPrgId(prgId);
		entity.setNotifyType(notifyType);
		prgDispatchNotifyService.save(entity);
		
		// 监听
		long maxDispatchTime = Long.parseLong(ContextPropertiesUtils.getProperty("prg_dispatch_time")) * 1000;
		Date maxDate = new Date(new Date().getTime() + maxDispatchTime);
		PrgDispatchNotify lastRec = new PrgDispatchNotify();
		while (true) {
			if (new Date().after(maxDate)) {
				break;
			}
			lastRec = prgDispatchNotifyService.getLastByPrgId(entity.getPrgId());
			Date dispatchTime = lastRec.getDispatchTime();
			if (dispatchTime != null) {
				break;
			}
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		if (null == lastRec.getDispatchTime()) {
			return 1; // 未启动调度
		}
		if (!lastRec.getDispatchStatus().equals(DispatchStatus.COMPLETED.getCode())) {
			return 2; // 未完成调度
		}
		if (null == lastRec.getDispatchResult() || lastRec.getDispatchResult().equals(DispatchResult.FAIL.getCode())) {
			return 3; // 调度失败
		}
		return 0;
	}
	
}
